#ifndef GAMELOGIC_OBJECTS_GAMEOBJECT_H_
#define GAMELOGIC_OBJECTS_GAMEOBJECT_H_

#include <Ogre.h>

#include "../../Common/Vec2d.h"
#include "./Data.h"
#include "./ObjectId.h"

#define DEFAULT_WALK_SPEED 0.01f

#define DEFAULT_BACKWARD_WALK_SPEED 0.05f

#define DEFAULT_STRAFE_SPEED 0.007f

/*
 * Typy obiektow:
 */

#define OT_GENERIC_BULLET 50

namespace GameLogic {

namespace Level {
class Tile;
} //namespace Level

namespace Objects {

/**
 * Reprezentuje obiekt znajdujacy sie na planszy. Przechowuje wszystkie zwiazane z nim dane.
 */
class GameObject {
public:
	typedef ObjectId IdType;

	static const int FLAG_LEFT;
	static const int FLAG_RIGHT;
	static const int FLAG_UP;
	static const int FLAG_DOWN;

	static const int FLAG_FIRE;

	enum CollisionState {
		csNotChecked,
		csChecked
	};

private:

	float radius_;

	IdType id_;

	CollisionState collision_state_;

	Data* data_;

	float z_;

	/*
	 * Znacznik uzywany przez serwer aby okreslic, czy od ostatniej propagacji stanu gry dane obiektu ulegly zmianie. Jezeli tak,
	 * to stan obiektu bedzie trzeba propagowac przy nastepnej aktualizacji.
	 */
	bool modified_;

	/**
	 * Znacznik ustawiany po modyfikacji zachowania obiektu przez gracza. Pozwala okreslic, czy
	 * zmiane zachowania nalezy propagowac do serwera: nie nalezy tego robic, jezeli zostala
	 * ona zmodyfikowana przez serwer.
	 */
	bool behaviour_changed_by_player_input_;

	/** Wiazanie obiektu z tilami. */
	Level::Tile** tile_hooks_;

	/** Scene node obiektu. Jest on przydzielany automatycznie podczas tworzenia obiektu. */
	Ogre::SceneNode* scene_node_;

public:

	GameObject( IdType id, float radius, Ogre::SceneNode* scene_node, Data* data = 0, float z = 0.0f );

	virtual ~GameObject();

	/**
	 * Montuje grafike zwiazana z obiektem w scenie.
	 */
	virtual void installGraphics();

	bool isModified() {
		return modified_;
	}

	void setModified( bool val ) {
		modified_ = val;
	}

	float getRadius() {
		return radius_;
	}

	Data* getData() {
		return data_;
	}

	IdType getId() { return id_; }

	bool isBehaviourChangedByPlayerInput() {
		return behaviour_changed_by_player_input_;
	}

	void setBehaviourChangedByPlayerInput( bool value ) {
		behaviour_changed_by_player_input_ = value;
	}

	CollisionState getCollisionState() {
		return collision_state_;
	}

	void setCollisionState( CollisionState cs ) {
		collision_state_ = cs;
	}

	Level::Tile** getTileHooks() { return tile_hooks_; }

	virtual float getWalkSpeed();

	virtual float getBackwardWalkSpeed();

	virtual float getStrafeSpeed();

	/* Przygotowuje obiekt do nowej klatki animacji. Resetuje wszystkie dane zwiazane
	 * z przetwarzaniem obiektu. */
	void resetTemporaryData() {
		collision_state_ = csNotChecked;
	}

	int getBehaviourFlags() {
		return data_->behaviour_flags;
	}

	int setBehaviourFlags( int flags ) {
		data_->behaviour_flags = flags;
	}

	Vec2f& getFacing() {
		return data_->facing;
	}

	long getTime() {
		return data_->time;
	}

	void positionOnScene();

	/*
	 * Zamienia stare dane obiektu na nowe.
	 */
	void replaceData( Data* data );

	const Vec2f& getPosition() { return data_->position; };

	/*
	 * Wbrew nazwie zwraca wspolrzedna Y obiektu :P.
	 */
	float getZPos() {
		return z_;
	}

	/* Ustawia nowy kat patrzenia obiektu. */
	void setFacing( const Vec2f& facing );

	/* Ustawia pozycje obiektu w swiecie. Nie aktualizuje pozycji SceneNode obiektu. */
	void setPosition( const Vec2f& pos ) {
		data_->position = pos;
		//scene_node_->setPosition( pos.x, getZPos(), pos.y );
	}

	/* Przesuwa obiekt o wektor. */
	void translate( const Vec2f& vect );

	/*****************************/
	/*      Obsluga zdarzen:     */
	/*****************************/

	/* Wolane po zderzeniu z innym obiektem: */
	virtual void onHit( GameObject* go );

	/* Wolane po zderzeniu z tilem: */
	virtual void onHitImpassableTile();

};

} //namespace Objects

typedef Objects::GameObject::IdType ObjectId;

} //namespace GameLogic

#endif /* GAMELOGIC_OBJECTS_GAMEOBJECT_H_ */
